﻿using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

namespace Core
{
    public class UIGrid : UIWidget
    {
        public readonly int MaxCellSize = 150;
        public float MaxSpacing = -1;

        public int W { get; private set; }
        public int H { get; private set; }
        public int Cnt { get; private set; }

        public GridLayoutGroup Layout { get; private set; }
        private Vector2 rectSize;
        private GameObject[,] goArr;
        private Vector3[,] posArr;

        /// <summary>
        /// 空闲队列
        /// </summary>
        private Queue<GameObject> pool = new();


        public override void Awake(GameObject go)
        {
            base.Awake(go);

            Layout = go.GetComponent<GridLayoutGroup>();
        }

        public override void Dispose()
        {
            if (IsDisposed) return;
            base.Dispose();

            MaxSpacing = -1;
        }

        public GameObject PopIdle()
        {
            if (pool.Count == 0)
            {
                return null;
            }
            var go = pool.Dequeue();
            //Debug.LogWarning($"Pop {m_pool.Count}");
            return go;
        }

        public void PushIdle(GameObject go)
        {
            go.transform.position = Vector3.zero;
            //Utils.Trans.SetPos(go, Vector3.zero);
            Utils.Trans.SetActive(go, false);
            pool.Enqueue(go);
            //Debug.LogWarning($"Push {m_pool.Count}");
        }

        public GameObject GetChild(int x, int y)
        {
            if (x < 0 || x >= W || y < 0 || y >= H)
            {
                return null;
            }

            return goArr[x, y];
        }
        public GameObject GetChild(Vector2Int pos)
        {
            return GetChild(pos.x, pos.y);
        }

        public Vector3 GetPos(int x, int y)
        {
            if (x < 0 || x >= W || y < 0 || y >= H)
            {
                return Vector3.zero;
            }

            return posArr[x, y];
        }

        public Vector3 GetPos(Vector2Int pos)
        {
            return GetPos(pos.x, pos.y);
        }

        public void SetAmount(int amount)
        {
            int cnt = 0;
            for (int i = 0; i < W; i++)
            {
                for (int j = 0; j < H; j++)
                {
                    var go = goArr[i, j];
                    Utils.Trans.SetActive(go, cnt < amount);

                    if (cnt >= amount)
                    {
                        pool.Enqueue(go);
                    }

                    cnt++;
                }
            }
        }

        public void RecordPos()
        {
            for (int i = 0; i < W; i++)
            {
                for (int j = 0; j < H; j++)
                {
                    var go = goArr[i, j];

                    posArr[i, j] = go.transform.position;
                }
            }
        }

        private void Foreach(Action<int, int, GameObject> func)
        {
            if (func == null) return;

            for (int i = 0; i < W; i++)
            {
                for (int j = 0; j < H; j++)
                {
                    var go = goArr[i, j];

                    func(i, j, go);
                }
            }
        }

        public void Resize(int width, int height)
        {
            Foreach((_, _, go) =>
            {
                Utils.Trans.SetActive(go, true);
            });

            W = width; H = height;
            Cnt = H * W;

            goArr = new GameObject[W, H];
            posArr = new Vector3[W, H];

            var rect = gameObject.GetComponent<RectTransform>().rect;
            rectSize.x = rect.width;
            rectSize.y = rect.height;

            Layout.childAlignment = TextAnchor.MiddleCenter;
            Layout.constraint = GridLayoutGroup.Constraint.FixedColumnCount;
            Layout.constraintCount = W;

            var cnt = transform.childCount;
            if (Cnt > cnt)
            {
                var delta = Cnt - cnt;
                var template = transform.GetChild(0).gameObject;
                for (int i = 0; i < delta; i++)
                {
                    var go = GameObject.Instantiate(template);
                    go.SetParent(transform);
                    go.SetLayer(gameObject.layer);
                    go.Reset();
                    go.name = $"{i + cnt + 1}";
                }
            }
            else if (Cnt < cnt)
            {
                for (int i = cnt - 1; i >= Cnt; i--)
                {
                    var go = transform.GetChild(i).gameObject;
                    Utils.Trans.Destroy(go);
                }
            }

            cnt = Cnt;
            for (int i = 0; i < cnt; i++)
            {
                var child = transform.GetChild(i);
                int p_x = i % W;
                int p_y = i / W;
                goArr[p_x, p_y] = child.gameObject;
            }

            var padding_h = Layout.padding.left + Layout.padding.right;
            var padding_v = Layout.padding.top + Layout.padding.bottom;

            float a = 8;
            float b = 2;

            var x = (rectSize.x - padding_h) / (W * a + (W - 1) * b);
            var y = (rectSize.y - padding_v) / (H * a + (H - 1) * b);

            var item_width = a * x;
            var item_height = a * y;

            var spacing = Mathf.Min(b * x, b * y);
            if (MaxSpacing >= 0)
            {
                var old_spacing = spacing;
                spacing = Mathf.Min(spacing, MaxSpacing);
                if (old_spacing > spacing)
                {
                    var delta = (old_spacing - spacing) * (W - 1) / W;
                    item_width += delta;
                    item_height += delta;
                }
            }
            Layout.spacing = new Vector2(spacing, spacing);

            var cell_size = Mathf.Min(item_width, item_height, MaxCellSize);
            Layout.cellSize = new Vector2(cell_size, cell_size);
        }
    }
}
